/*
 * OpenParts
 * A dynamic-loading components framework for GWT
 * Copyright (C) 2011 Christophe Bouthier  [chris{AT}binary-gastronome{DOT}fr]
 *
 * This work is partially based on work I have done at INRIA (http://www.inria.fr) 
 * in the context of the Qualipso European Project (http://qualipso.org/),
 * The work done at INRIA is Copyright (C) 2006-2011 INRIA
 *
 * This work is distributed under the LGPL version 3
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version 3
 * as published by the Free Software Foundation. See the GNU
 * Lesser General Public License in LGPL.txt for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package fr.openparts.OpenParts.client;

import static com.google.gwt.dom.client.Style.Unit.PX;

import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Node;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * OPPartContainer is the replacement for RootPanel, it's the panel that will contains the slot and to which the part will be added. Solution is so simple once
 * you understand the model and formulate the problem correctly.
 * 
 * @author Christophe Bouthier [chris{AT}binary-gastronome{DOT}fr]
 * @creation.date 08 January 2010
 */
public class OPPartContainer extends SimplePanel {

    /**
     * Private constructor, can be build only from {@link #get(String)}.
     * 
     * @param element
     *            the contained element
     */
    private OPPartContainer(Element element) {
        super(element);
        onAttach();
    }

    /**
     * Return an OPPartContainer for the given slot. Return null if there is no such slot.
     * 
     * @param slotId
     *            the searched slot id. Shouldn't be null.
     * @return an OPPartContainer on the given slot.
     */
    public static OPPartContainer get(final String slotId) {
        assert slotId != null : "parameter slotId shouldn't be null";

        Element slot = DOM.getElementById(slotId);
        if (slot == null) {
            return null;
        }

        return new OPPartContainer(slot);
    }

    /**
     * Add the given widget as children of this part container, and set its constraints so that it fills up its parent. Remove all widget attached to the slot
     * if necessary.
     * 
     * @see com.google.gwt.user.client.ui.SimplePanel#add(com.google.gwt.user.client.ui.Widget)
     * 
     * @param child
     *            the widget to add. Shouldn't be null.
     */
    @Override
    public void add(final Widget child) {
        assert child != null : "parameter child shouldn't be null";

        // clean up contained widget if necessary
        cleanLoadingWidget();

        super.add(child);
        fillParent(child.getElement());
    }

    /**
     * Remove all widget attached to the slot if there is one (a "loading..." message in particular, see {@link OPSlot#add(Widget)}.
     */
    protected void cleanLoadingWidget() {
        Element container = getElement();
        
        if (container.hasChildNodes()) {
            Node childNode = null;
            while ((childNode = container.getFirstChild()) != null) {
                container.removeChild(childNode);
            }
        }
    }

    /**
     * Set the constraints on the given element so that it fills up its parent.
     * 
     * @param elem
     *            the element to set constraints on. Shouldn't be null.
     */
    public void fillParent(final Element elem) {
        Style style = elem.getStyle();
        style.setPosition(Position.ABSOLUTE);
        style.setLeft(0, PX);
        style.setTop(0, PX);
        style.setRight(0, PX);
        style.setBottom(0, PX);
    }

}
